iT邦幫忙

2022 iThome 鐵人賽

DAY 15
1
Software Development

30天學會Golang系列 第 15

Day15 - Go的 WaitGroup

  • 分享至 

  • xImage
  •  

WaitGroup

要介紹 WaitGroup 前,我們還是用之前的程式碼來小小修改一下,下面是昨天 day14 的程式碼

// version 3 資料蒐集完就 print
func doWorker3(id int, c chan int, done chan bool) {
	for n := range c {
		fmt.Printf("Worker %d received %c \n", id, n)
		done <- true
	}
}

type worker3 struct {
	in   chan int
	done chan bool
}

func createWorker3(id int) worker3 {
	w := worker3{
		in:   make(chan int),
		done: make(chan bool),
	}
	go doWorker3(id, w.in, w.done)
	return w
}

func chanDemo3() {
	var workers [10]worker3
	for i := 0; i < 10; i++ {
		workers[i] = createWorker3(i)
	}

	for i, worker := range workers {
		worker.in <- 'a' + i // send
	}

	for i := 0; i < 10; i++ {
		<-workers[i].done // receive
	}

	for i, worker := range workers {
		worker.in <- 'A' + i
	}

	for i := 0; i < 10; i++ {
		<-workers[i].done // receive
	}
}

接下來的程式碼中要導入另一個專門針對 goroutine 的東西:WaitGroup,根據 參考來源3 與其介紹原始代碼得知

  • WaitGroup 是用來等待一群 Goroutine 的功用
  • 透過 Add 來加入 Goroutine,而每一個 Goroutine 做完之後都需要呼叫 Done,Done 相當於 Add(-1)
  • 同時使用 Wait 可以來進行 block,直到所有的 Goroutine 都已經結束

修改為加入 WaitGroup 的版本:

// // version 4 資料邊蒐集編輸出
func doWorker4(id int, c chan int, wg *sync.WaitGroup) {
// 	for n := range c {
// 		fmt.Printf("Worker %d received %c \n", id, n)
// 		// done <- true // 刪除
		wg.Done()
// 	}
// }

// type worker4 struct {
// 	in chan int
	wg *sync.WaitGroup
// }

func createWorker4(id int, wg *sync.WaitGroup) worker4 {
// 	w := worker4{
// 		in: make(chan int),
		wg: wg,
// 	}
	go doWorker4(id, w.in, wg)
// 	return w
// }

// func chanDemo4() {
	var wg sync.WaitGroup

// 	var workers [10]worker4
// 	for i := 0; i < 10; i++ {
		workers[i] = createWorker4(i, &wg)
// 	}

	wg.Add(20)

// 	for i, worker := range workers {
// 		worker.in <- 'a' + i // send
// 	}

// 	// for i := 0; i < 10; i++ {     // 刪除
// 	// 	<-workers[i].done // receive // 刪除
// 	// }                             // 刪除

// 	for i, worker := range workers {
// 		worker.in <- 'A' + i
// 	}

// 	// for i := 0; i < 10; i++ {     // 刪除
// 	// 	<-workers[i].done // receive // 刪除
// 	// }                             // 刪除

	wg.Wait()

// }

輸出結果為:

Worker 0 received a 
Worker 0 received A 
Worker 1 received b 
Worker 1 received B 
Worker 9 received j 
Worker 2 received c 
Worker 2 received C 
Worker 3 received d 
Worker 4 received e 
Worker 4 received E 
Worker 3 received D 
Worker 6 received g 
Worker 7 received h 
Worker 8 received i 
Worker 5 received f 
Worker 5 received F 
Worker 9 received J 
Worker 7 received H 
Worker 6 received G 
Worker 8 received I 

如此一來可以看到大小寫混在一起,表示他是邊搜集邊輸出。

但其中值得注意的是,在使用 WaitGroup 要注意 Add(數量) 中的數量必須與 groutine 開的數量一樣,否則都會引發 panic

  • 假設 Add(數量) 的數量 > groutine 會引發下面情形
fatal error: all goroutines are asleep - deadlock!
  • 假設 Add(數量) 的數量 < groutine 會引發下面情形
panic: sync: negative WaitGroup counter
第15天報到,我感覺 channel 與 WaitGroup 使用情境好像有點不同,下一篇先來介紹 Mutex,在 go 裡面這三個是專門來處理 goroutine 的東西,後面應該會找個時間為這三個東東好好來個總整理

參考來源

  1. https://coding.m.imooc.com/classindex.html?cid=180
  2. https://clouding.city/go/mutex-rwmutex/
  3. https://reurl.cc/ERNRRk

代碼連結

https://github.com/luckyuho/ithome30-golang/tree/main/day15


上一篇
Day14 - Go的 channel (下)
下一篇
Day16 - Go的 Mutex (互斥鎖)
系列文
30天學會Golang31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言